#!/usr/bin/env bash

__rvm_md5_calculate()
{
  rvm_debug "Calculate md5 checksum for $@"

  \typeset _sum
  if
    builtin command -v md5 > /dev/null 2>&1
  then
    _sum=$(md5 "$@")
    echo ${_sum##* }
    return 0
  elif
    builtin command -v md5sum > /dev/null 2>&1
  then
    _sum=$(md5sum "$@")
    echo ${_sum%% *}
    return 0
  elif
    builtin command -v gmd5sum > /dev/null 2>&1
  then
    _sum=$(gmd5sum "$@")
    echo ${_sum%% *}
    return 0
  else
    for _path in /usr/gnu/bin /opt/csw/bin /sbin /bin /usr/bin /usr/sbin
    do
      if
        [[ -x "${_path}/md5" ]]
      then
        _sum=$(${_path}/md5 "$@")
        echo ${_sum##* }
        return 0
      elif
        [[ -x "${_path}/md5sum" ]]
      then
        _sum=$(${_path}/md5sum "$@")
        echo ${_sum%% *}
        return 0
      elif
        [[ -x "${_path}/gmd5sum" ]]
      then
        _sum=$(${_path}/gmd5sum "$@")
        echo ${_sum%% *}
        return 0
      fi
    done
  fi

  rvm_error "Neither of md5sum, md5, gmd5sum found in the PATH"
  return 1
}

__rvm_sha__calculate()
{
  rvm_debug "Calculate sha512 checksum for $@"

  \typeset bits _sum
  bits=${1:-512}
  shift

  if
    builtin command -v sha${bits}sum >/dev/null
  then
    _sum=$(sha${bits}sum    "$@")
    echo ${_sum% *}
    return 0
  elif
    builtin command -v sha${bits}    >/dev/null
  then
    _sum=$(sha${bits}       "$@")
    if [[ "${_sum%% *}" == "SHA${bits}" ]]
    then echo ${_sum##* } # take last of:  SHA512 (file) = ....
    else echo ${_sum% *}  # take first of: ... file
    fi
    return 0
  elif
    builtin command -v shasum    >/dev/null
  then
    _sum=$(shasum -a${bits} "$@")
    echo ${_sum% *}
    return 0
  elif
    # Drop-in for Solaris 10
    builtin command -v /opt/csw/bin/shasum >/dev/null
  then
    _sum=$(/opt/csw/bin/shasum -a${bits} "$@")
    echo ${_sum% *}
    return 0
  fi

  rvm_error "Neither sha512sum nor shasum found in the PATH"
  return 1
}

# __rvm_checksum_calculate_file {file}
# ENV out: _checksum_md5 _checksum_sha512
__rvm_checksum_calculate_file()
{
  rvm_debug "Calculate checksums for file ${1}"

  _checksum_md5="$(    __rvm_md5_calculate      "${1:-}" )"
  _checksum_sha512="$( __rvm_sha__calculate 512 "${1:-}" )"
}

__rvm_checksum_none()
{
  [[ -z "${_checksum_md5:-}" && -z "${_checksum_sha512:-}" ]]
}

__rvm_checksum_any()
{
  [[ -n "${_checksum_md5:-}" || -n "${_checksum_sha512:-}" ]]
}

__rvm_checksum_all()
{
  [[ -n "${_checksum_md5:-}" && -n "${_checksum_sha512:-}" ]]
}

# __rvm_checksum_validate_file {file}
# ENV in: _checksum_md5 _checksum_sha512
__rvm_checksum_validate_file()
{
  rvm_debug "Validating checksums for file ${1}"

  if
    __rvm_checksum_any
  then
    rvm_debug "    ...checksums found in db"
  else
    rvm_debug "    ...checksums not found in db"
    return 1
  fi

  # Validate md5 checksum
  if
    [[ -n "${_checksum_md5:-}" ]]
  then
    rvm_debug "Validating md5 checksum"
    if
      [[ "$(__rvm_md5_calculate "${1:-}")" == "${_checksum_md5:-}" ]]
    then
      rvm_debug "    ...md5 checksum is valid!"
    else
      rvm_debug "    ...md5 checksum is not valid!!!"
      return 2
    fi
  fi

  # Validate sha512 checksum
  if
    [[ -n "${_checksum_sha512:-}" ]]
  then
    rvm_debug "Validating sha15 checksum"

    if
      [[ "$(__rvm_sha__calculate 512 "${1:-}")" == "${_checksum_sha512:-}" ]]
    then
      rvm_debug "    ...sha512 checksum is valid!"
    else
      rvm_debug "    ...sha512 checksum is not valid!!!"
      return 3
    fi
  fi

  return 0
}

# __rvm_checksum_read {name...}
# name - list of names to check, like:
#
#     __rvm_checksum_read https://rvm.io/binaries/.../ruby-1.9.3-p194.tar.bz2 bin-ruby-1.9.3-p194.tar.bz2
#
# ENV in/out: _checksum_md5 _checksum_sha512
__rvm_checksum_read()
{
  rvm_debug "Load checksums for $1"

  __rvm_checksum_none || return 0
  \typeset _type _value _name
  \typeset -a _list
  list=()

  for _name in "$@"
  do
    list+=( "$_name" )
    if
      [[ "$_name" == *"?"* ]] # try url without ?... like ?rvm={version}
    then
      list+=( "${_name%\?*}" )
    fi
  done

  for _name in "${list[@]}"
  do
    _checksum_md5="$(      __rvm_db_ "$rvm_path/config/md5"    "$_name" | \command \head -n 1 )"
    [[ -n "${_checksum_md5:-}" ]] ||
      _checksum_md5="$(    __rvm_db_ "$rvm_user_path/md5"      "$_name" | \command \head -n 1 )"

    _checksum_sha512="$(   __rvm_db_ "$rvm_path/config/sha512" "$_name" | \command \head -n 1 )"
    [[ -n "${_checksum_sha512:-}" ]] ||
      _checksum_sha512="$( __rvm_db_ "$rvm_user_path/sha512"   "$_name" | \command \head -n 1 )"

    __rvm_checksum_none || return 0
  done

  rvm_debug "    ...checksums not found"
  return 1 # not found
}

# Record checksums in user settings
# Usage: __rvm_checksum_write {name}
# ENV in/out: _checksum_md5 _checksum_sha512
__rvm_checksum_write()
{
  [[ -n "${1:-}" ]]  || return 1
  __rvm_checksum_any || return 1

  [[ -z "${_checksum_md5:-}"    ]] || __rvm_db_ "$rvm_user_path/md5"    "${1:-}" "${_checksum_md5:-}"
  [[ -z "${_checksum_sha512:-}" ]] || __rvm_db_ "$rvm_user_path/sha512" "${1:-}" "${_checksum_sha512:-}"

  return 0
}
